# This file is a part of the open-eBackup project.
# This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
# If a copy of the MPL was not distributed with this file, You can obtain one at
# http://mozilla.org/MPL/2.0/.
#
# Copyright (c) [2024] Huawei Technologies Co.,Ltd.
#
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
import json
import sys
import unittest
from unittest import mock
from unittest.mock import MagicMock, patch

from pydantic import BaseModel

from app.common.enums.resource_enum import DeployTypeEnum
from tests.test_cases import common_mocker  # noqa

class MachineParameters(BaseModel):
    uuid: str = ""
    mo_id: str = ""
    mac_address: str = ""

class DiscoveryManagerTest(unittest.TestCase):
    def setUp(self) -> None:
        self._mock_common_db_init = mock.patch("app.common.database.Database.initialize", mock.Mock)
        self._mock_common_db_init.start()
        from tests.test_cases.tools.kafka_producer_mock import KafkaProducerMock
        self._mock_kafka_producer = mock.patch("confluent_kafka.Producer", MagicMock(return_value=KafkaProducerMock()))
        self._mock_kafka_producer.start()
        mock.patch("app.common.deploy_type.DeployType.get_deploy_type",
                   MagicMock(return_value=DeployTypeEnum.X8000)).start()
        sys.modules['pyVmomi.Iso8601'] = MagicMock()
        sys.modules['app.resource.service.vmware.service_instance_manager'] = MagicMock()

        # 样本数据
        sys.modules['app.protection.object.service.batch_protection_service'] = MagicMock()
        res1 = MachineParameters(uuid="vm1", mo_id="mo1", mac_address='{"00:11:22": "vim.vm.device.VirtualE1000"}')
        res2 = MachineParameters(uuid="vm2", mo_id="mo2", mac_address='{"AA:BB:CC": "vim.vm.device.VirtualE1000"}')
        res3 = MachineParameters(uuid="vm3", mo_id="mo3", mac_address='{"11:22:33": "vim.vm.device.VirtualE1000"}')
        res4 = MachineParameters(uuid="vm3", mo_id="mo3", mac_address='{}')
        self.sample_resources = [
            res1,
            res2,
            res3,
            res4,
            {"uuid": "vm1", "mac_address": '{"vim.vm.device.VirtualE1000": "00:11:22"}', "mo_id": "mo1"},
            {"uuid": "vm2", "mac_address": '{"vim.vm.device.VirtualE1000": "AA:BB:CC"}', "mo_id": "mo2"},
            {"uuid": "vm3", "mac_address": '{"vim.vm.device.VirtualE1000": "11:22:33"}', "mo_id": "mo3"}
        ]

    def tearDown(self) -> None:
        del sys.modules['pyVmomi.Iso8601']

    @patch("app.resource.service.common.resource_service.query_environment", MagicMock(return_value=None))
    @patch("app.common.toolkit.modify_task_log", MagicMock())
    @patch("app.common.toolkit.create_job_center_task", MagicMock(return_value={'job_id': '1'}))
    @patch("app.common.toolkit.complete_job_center_task", MagicMock())
    def test_register_env_success(self):
        """
        *用例场景：测试注册环境成功
        *前置条件：环境信息参数正确
        *检查点: 无异常信息返回
        """
        from app.common.enums.resource_enum import ResourceSubTypeEnum
        from app.resource.schemas.env_schemas import ScanEnvSchema
        from app.resource.discovery.plugins.vmware_discovery_plugin import VMwareDiscoveryPlugin
        from app.resource.discovery.res_discovery_plugin import DiscoveryManager
        from app.common.clients.scheduler_client import SchedulerClient

        params = ScanEnvSchema(
            verify_cert=1,
            sub_type=ResourceSubTypeEnum.vCenter.value,
            uuid="12345",
            endpoint="1.1.1.1",
            port=443,
            extend_context={
                'cert_name': 'cert_name1',
                'crl_name': 'crl_name1',
                'certification': 'certification1',
                'revocation_list': 'revocation_list1',
            },
            job_id="11111111"
        )
        with mock.patch.object(VMwareDiscoveryPlugin, "do_scan_env", MagicMock()), \
                mock.patch.object(SchedulerClient, "submit_interval_job", MagicMock()), \
                mock.patch.object(DiscoveryManager, "heartbeat", MagicMock()):
            DiscoveryManager(ResourceSubTypeEnum.vCenter.value).register_env(params)
            self.assertIsNotNone(params)

    @patch("app.resource.service.common.resource_service.query_environment", MagicMock(return_value=[{}]))
    @patch("app.common.toolkit.query_job_list", MagicMock(return_value=json.dumps({"totalCount": 0})))
    @patch("app.common.toolkit.modify_task_log", MagicMock())
    @patch("app.common.toolkit.complete_job_center_task", MagicMock())
    def test_manual_scan_env_success(self):
        """
        *用例场景：测试手动扫描环境成功
        *前置条件：环境信息参数正确
        *检查点: 无异常信息返回
        """
        from app.common.enums.resource_enum import ResourceSubTypeEnum
        from app.resource.schemas.env_schemas import ScanEnvSchema
        from app.resource.discovery.plugins.vmware_discovery_plugin import VMwareDiscoveryPlugin
        from app.resource.discovery.res_discovery_plugin import DiscoveryManager

        params = ScanEnvSchema(
            verify_cert=1,
            sub_type=ResourceSubTypeEnum.vCenter.value,
            uuid="12345",
            endpoint="1.1.1.1",
            port=443,
            job_id='job_1',
            extend_context={
                'cert_name': 'cert_name1',
                'crl_name': 'crl_name1',
                'certification': 'certification1',
                'revocation_list': 'revocation_list1',
            }
        )
        with mock.patch.object(VMwareDiscoveryPlugin, "do_scan_env", MagicMock()), \
                mock.patch.object(DiscoveryManager, "heartbeat", MagicMock()):
            self.assertIsNone(DiscoveryManager(ResourceSubTypeEnum.vCenter.value).manual_scan_env('123', '123'))

    ### 1. 测试 _query_agent_macs ###
    @patch("app.resource.discovery.plugins.vmware_discovery_plugin.curd")
    @patch("app.resource.discovery.plugins.vmware_discovery_plugin.database.session")
    def test_query_agent_macs_with_data(self, mock_session_factory, mock_curd):
        from app.resource.discovery.plugins.vmware_discovery_plugin import VMwareDiscoveryPlugin
        """测试正常Agent数据查询"""
        # Mock数据库返回
        mock_agents = [
            MagicMock(agent_id="agent1", mac_address="00:11:22"),
            MagicMock(agent_id="agent1", mac_address="AA:BB:CC"),
            MagicMock(agent_id="agent2", mac_address="FF:FF:FF")
        ]
        mock_session_factory.return_value.__enter__.return_value.query.return_value.join.return_value.filter.return_value.all.return_value = mock_agents

        # 执行方法
        mac_to_agent = VMwareDiscoveryPlugin()._query_agent_macs()

        # 验证结果
        self.assertEqual(mac_to_agent, {
            "00:11:22": "agent1",
            "AA:BB:CC": "agent1",
            "FF:FF:FF": "agent2"
        })

    @patch("app.resource.discovery.plugins.vmware_discovery_plugin.curd")
    @patch("app.resource.discovery.plugins.vmware_discovery_plugin.database.session")
    def test_query_agent_macs_empty(self, mock_session, mock_curd):
        """测试无Agent数据时返回空字典"""
        from app.resource.discovery.plugins.vmware_discovery_plugin import VMwareDiscoveryPlugin
        mac_to_agent = VMwareDiscoveryPlugin()._query_agent_macs()
        self.assertEqual(mac_to_agent, {})

    ### 2. 测试 _filter_and_record ###
    @patch("app.resource.discovery.plugins.vmware_discovery_plugin.curd")
    @patch("app.resource.discovery.plugins.vmware_discovery_plugin.database.session")
    def test_filter_and_record_normal(self, mock_db, mock_curd):
        """测试正常过滤和记录流程"""
        from app.resource.discovery.plugins.vmware_discovery_plugin import VMwareDiscoveryPlugin
        # Mock _query_agent_macs 返回值
        with mock.patch.object(VMwareDiscoveryPlugin, "_query_agent_macs", return_value={"00:11:22": "agent1"}):
            mock_db.return_value.__enter__.return_value.query.return_value.filter.return_value.first.return_value = None
            # 执行测试
            filtered_resources = VMwareDiscoveryPlugin()._filter_and_record(self.sample_resources)

            # 验证过滤结果
            self.assertEqual(len(filtered_resources), 6)
            self.assertEqual(filtered_resources[0].uuid, "vm2")
            self.assertEqual(filtered_resources[1].uuid, "vm3")

            # 验证数据库写入
            mock_session = mock_db.return_value.__enter__.return_value
            mock_session.add_all.assert_called_once()
            added_record = mock_session.add_all.call_args[0][0][0]
            self.assertEqual(added_record.resource_id, "agent1")
            self.assertEqual(added_record.value, "mo1")

    @patch("app.resource.discovery.plugins.vmware_discovery_plugin.curd")
    @patch('app.resource.discovery.plugins.vmware_discovery_plugin.database.session')
    def test_filter_and_record_duplicate(self, mock_db, mock_curd):
        """测试重复mo_id不重复记录"""
        from app.resource.discovery.plugins.vmware_discovery_plugin import VMwareDiscoveryPlugin
        # Mock _query_agent_macs 返回值
        with mock.patch.object(VMwareDiscoveryPlugin, "_query_agent_macs", return_value={"00:11:22": "agent1"}):
            # Mock数据库已有记录
            mock_session = mock_db.return_value.__enter__.return_value
            mock_session.query.return_value.filter.return_value.first.return_value = MagicMock()

            # 执行测试
            VMwareDiscoveryPlugin()._filter_and_record(self.sample_resources)

            # 验证未写入重复记录
            mock_session.add.assert_not_called()

    def test_filter_and_record_invalid_mac_json(self):
        """测试无效MAC地址JSON处理"""
        from app.resource.discovery.plugins.vmware_discovery_plugin import VMwareDiscoveryPlugin
        with mock.patch.object(VMwareDiscoveryPlugin, "_query_agent_macs", return_value={}):
            res = VMwareDiscoveryPlugin()._filter_and_record([{"uuid": "vm1", "mac_address": "invalid_json"}])
            self.assertEqual(len(res), 1)

if __name__ == '__main__':
    unittest.main(verbosity=2)
